
function Get-ContentDeploymentJob
{
Param(
  [Parameter(Mandatory=$false,Position=1)][string]$Identity
)
	[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
	
	foreach($job in $XmlConfig.Root.ContentDeployment.Export.Jobs.Job)
	{
		if ( ($Identity -ne "")-and($job.Name -ne $Identity))
		{	continue;}
		$job
	}
}

function Get-ContentDeploymentJobChangesDistinct
{
Param(
  [Parameter(Mandatory=$true,Position=1)][string]$Identity
)
	[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
	
	$changes = Get-ContentDeploymentJobChanges -Identity $Identity
	
	$ids = $changes | select UniqueId -Unique
	$changeLog  = @()
	$skippingItems = $changes | ? {$_.ChangeType -eq  [Microsoft.SharePoint.SPChangeType]::Delete} | select UniqueId
	foreach($change in $changes)
	{
		if (($change -eq $null)-or ($skippingItems.UniqueId -contains $change.UniqueId))	
		{			
			Write-Host "Skipping $($change.UniqueId)" -foregroundcolor red
			continue;
			# Caller takes care of handling $null results
		}
		
		Write-Host "$($change.ChangeType.ToString()) - $($change.GetType().ToString()) - $($change.Time)"
		if ($change -is [Microsoft.SharePoint.SPChangeItem])
		{
			if ( ($changeLog | select UniqueId -Unique) -match $change.UniqueId){continue;}
			
			if ( ($change.ChangeType -eq [Microsoft.SharePoint.SPChangeType]::Add)-or ($change.ChangeType -eq [Microsoft.SharePoint.SPChangeType]::Update) )
			{
				$changeLog += new-object -typename psobject -property @{
					UniqueId			=	$change.UniqueId;
					Type 				= 	[Microsoft.SharePoint.Deployment.SPDeploymentObjectType]::ListItem;
					ChangeToken		 	=	$change.ChangeToken;
					ParentId			= 	$change.ListId;
				}
			}
		}
	}
	
	foreach($entry in $changeLog)
	{
		$exportObject = New-Object Microsoft.SharePoint.Deployment.SPExportObject
		$exportObject.Id 				= 	$entry.UniqueId
		$exportObject.Type 				=	$entry.Type
		$exportObject.ExportChangeToken =	$entry.ChangeToken
		$exportObject.ParentId 			= 	$entry.ParentId
		$exportObject
	}	
}

function Get-ContentDeploymentJobChanges
{
Param(
  [Parameter(Mandatory=$false,Position=1)][string]$Identity,
  [Parameter(Mandatory=$false,Position=2)][string]$Object
)
	[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
	
	$job = Get-ContentDeploymentJob $Identity
	if ( $job -eq $null) {break;}
	$web = Get-SPWeb $job.WebUrl
	foreach($jobItem in $job.JobItems.JobItem)
	{
		if (($object -ne "")-and($object -ne $jobItem.Name)){continue;}
		
		$token = Get-Token -Identity $Identity
		if ( $token -eq $null) {continue;}
		
		$timestamp = [DateTime]::Parse($token.Timestamp)
		
		if ( $jobItem.Type -eq "List")		
		{
			Write-Host "Check changes for list $($jobItem.Name)"
			
			if (($list = $web.Lists | ? {$_.RootFolder.Name -eq $jobItem.Name} ) -eq $null)
			{
				if (($list = $web.Lists | ? {$_.ID -eq $jobItem.Name}) -eq $null)
				{
					Write-Host "List $($jobItem.Name) not found."
					continue;
				}
			}
			$changeToken = New-Object Microsoft.SharePoint.SPChangeToken(3,$list.Id,(new-object DateTime(($timestamp).Year,($timestamp).Month,($timestamp).Day,($timestamp).Hour,($timestamp).Minute,($timestamp).Secound)).ToUniversalTime())
			
			$list.GetChanges($changeToken)
		}

	}
	$web.Dispose()
}

function Run-ContentDeploymentJob
{
	Param(
	  [Parameter(Mandatory=$true,Position=1)][string]$Identity,
	  [Parameter(Mandatory=$true,Position=2)][ValidateSet('Full','Incremental')][string]$Mode,
	  [switch]$Demo = $false
	)
	
	$job = Get-ContentDeploymentJob $Identity
	if ( $job -eq $null) 
	{
		Write-Host "Job $identity not found."
		return;
	}
	
	$directory = $XmlConfig.Root.ContentDeployment.Export.FileLocation + "\\" + [system.guid]::newguid().ToString()
	
	$settings = New-Object Microsoft.SharePoint.Deployment.SPExportSettings
	$settings.SiteUrl = $job.SiteUrl
	$settings.FileLocation = $directory
	$settings.BaseFileName = $job.Name
	$settings.IncludeVersions = [Microsoft.SharePoint.Deployment.SPIncludeVersions]::LastMajor;
	if ( $job.ExcludeDependencies -eq "1")	{$settings.ExcludeDependencies = $true}	else	{$settings.ExcludeDependencies = $false}
	if ( $job.FileCompression -eq "1")	{$settings.FileCompression = $true}	else	{$settings.FileCompression = $false}
	
	
	if ( $job.Type -eq "List")
	{
		# List MODE
		
		if ($Mode -eq "Full")
		{
			$web = Get-SPWeb $job.WebUrl
			foreach($jobItem in $job.JobItems.JobItem)
			{
				if (($list = $web.Lists | ? {$_.RootFolder.Name -eq $jobItem.Name} ) -eq $null)
				{
					if (($list = $web.Lists | ? {$_.ID -eq $jobItem.Name}) -eq $null)
					{
						Write-Host "List $($jobItem.Name) not found."
						continue;
					}
				}
				Write-Host "Adding $($jobItem.Name) to package." -foregroundcolor green
				
				$exportObject = New-Object Microsoft.SharePoint.Deployment.SPExportObject
				$exportObject.Id = $list.Id
				$exportObjectIncludeDescendants =  [Microsoft.SharePoint.Deployment.SPIncludeDescendants]::ALL
				$exportObject.Type = [Microsoft.SharePoint.Deployment.SPDeploymentObjectType]::List
				$settings.ExportObjects.Add($exportObject)
			}
		}
		else
		{
			$Mode = "Incremental"
			# Warning INCREMENTAL runs are allowed until the past run was imported
			
			$settings.FileCompression = $false # Compression is not supported for incremental jobs
			
			if (($token.Imported -eq $false)-and ($token.Mode -eq "Incremental")) 
			{
				Write-Host "No more incremental exports allowed" -foregroundcolor red
				return;
			}
			$contents  = Get-ContentDeploymentJobChangesDistinct -Identity $Identity
			foreach($item in $contents)
			{
				if ($item -eq $null)
				{
					Write-Host "No changes, no incremental export. Bye"
					return;
				}
				$settings.ExportObjects.Add($item)
			}
		}	
	}	
	elseif ( $job.Type -eq "Web" )
	{
		Write-Host "Adding $($jobItem.Name) to package." -foregroundcolor green
		
		$web = Get-SPWeb $job.WebUrl
			
		$exportObject = New-Object Microsoft.SharePoint.Deployment.SPExportObject
		$exportObject.Id = $web.Id
		$exportObjectIncludeDescendants =  [Microsoft.SharePoint.Deployment.SPIncludeDescendants]::ALL
		$exportObject.Type = [Microsoft.SharePoint.Deployment.SPDeploymentObjectType]::Web
		$settings.ExportObjects.Add($exportObject)
	}
	elseif ( $job.Type -eq "Site" )
	{
		if ( $Mode -eq "Full")
		{
			Write-Host "Adding site $($job.SiteUrl) to package." -foregroundcolor green
		
			$site = Get-SPSite $job.SiteUrl
			
			$exportObject = New-Object Microsoft.SharePoint.Deployment.SPExportObject
			$exportObject.Id = $site.Id
			$exportObjectIncludeDescendants =  [Microsoft.SharePoint.Deployment.SPIncludeDescendants]::ALL
			$exportObject.Type = [Microsoft.SharePoint.Deployment.SPDeploymentObjectType]::Site
			$settings.ExportObjects.Add($exportObject)
		}
		else
		{
			Write-Host "Adding site $($job.SiteUrl) to package." -foregroundcolor green
			
			$token = Get-Token -Identity $Identity
			if ( $token -eq $null) {continue;}
			$timestamp = [DateTime]::Parse($token.Timestamp)
			
			$site = Get-SPSite $job.SiteUrl
			
			$changeToken = New-Object Microsoft.SharePoint.SPChangeToken(1,$site.Id,(new-object DateTime(($timestamp).Year,($timestamp).Month,($timestamp).Day,($timestamp).Hour,($timestamp).Minute,($timestamp).Secound)).ToUniversalTime())
			$exportObject = New-Object Microsoft.SharePoint.Deployment.SPExportObject
			$exportObject.Id = $site.Id
			$exportObjectIncludeDescendants =  [Microsoft.SharePoint.Deployment.SPIncludeDescendants]::ALL
			$exportObject.Type = [Microsoft.SharePoint.Deployment.SPDeploymentObjectType]::Site
			
			$settings.ExportMethod = [Microsoft.SharePoint.Deployment.SPExportMethodType]::ExportChanges;
			$settings.ExportChangeToken = $changeToken
		}
	}

	$export = New-Object Microsoft.SharePoint.Deployment.SPExport($settings)
	
	if ($demo -eq $false)
	{
		mkdir $directory
		$export.Run()
		Add-Token -Job $Job.Name -Timestamp (get-date).ToString("yyyy.MM.dd HH:mm:ss") -Directory $directory -Imported $false -Mode $mode
	}
}